﻿using Transformable_Engine_v2.Engine.Transformable_Math.Geometry;

namespace Transformable_Engine_v2.Engine.Helper
{
    public static class CollisionHelper
    {
        /// <summary>
        /// Detects if a point is inside a rectangle
        /// </summary>
        /// <param name="rectangle"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public static bool Intersects(TE_Rectangle rectangle, TE_Vector2 point)
        {
            return Intersects(point, rectangle);
        }

        public static TE_Vector2 GetFurthestInDirection(this TE_Rectangle rectangle, TE_Vector2 point, TE_Vector2 direction)
        {
            float distanceX = 0, distanceY = 0;

            if(direction.X > 0)
            {
                distanceX = (rectangle.Right - point.X) / direction.X;
            }
            else if(direction.X < 0)
            {
                distanceX = (rectangle.Left - point.X) / direction.X;
            }

            if(direction.Y > 0)
            {
                distanceY = (rectangle.Bottom - point.Y) / direction.Y;
            }
            else if(direction.Y < 0)
            {
                distanceY = (rectangle.Top - point.Y) / direction.Y;
            }

            if(direction.Y == 0 || distanceX < distanceY)
            {
                var result = direction * distanceX;
                return result;
            }
            if(direction.X == 0 || distanceX >= distanceY)
            {
                var result = direction * distanceY;
                return result;
            }

            return null;
        }

        /// <summary>
        /// Detects if a point is inside a rectangle
        /// </summary>
        /// <param name="point"></param>
        /// <param name="rectangle"></param>
        /// <returns></returns>
        public static bool Intersects(TE_Vector2 point, TE_Rectangle rectangle)
        {
            return point.X >= rectangle.Left && point.X <= rectangle.Right && 
                    point.Y >= rectangle.Top && point.Y <= rectangle.Bottom;
        }

        /// <summary>
        /// Detects if a point is inside a circle
        /// </summary>
        /// <param name="point"></param>
        /// <param name="circle"></param>
        /// <returns></returns>
        public static bool Intersects(TE_Vector2 point, TE_Circle circle)
        {
            return (point - circle.Center).Length < circle.Radius;
        }

        /// <summary>
        /// Detects if a point is inside a circle
        /// </summary>
        /// <param name="circle"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public static bool Intersects(TE_Circle circle, TE_Vector2 point)
        {
            return Intersects(point, circle);
        }
        
        /// <summary>
        /// Detects if two circles intersect
        /// </summary>
        /// <param name="circle1"></param>
        /// <param name="circle2"></param>
        /// <returns></returns>
        public static bool Intersects(TE_Circle circle1, TE_Circle circle2)
        {
            return (circle1.Center - circle2.Center).Length < circle1.Radius + circle2.Radius;
        }

        /// <summary>
        /// Detects if two rectangles intersect
        /// </summary>
        /// <param name="rectangle1"></param>
        /// <param name="rectangle2"></param>
        /// <returns></returns>
        public static bool Intersects(TE_Rectangle rectangle1, TE_Rectangle rectangle2)
        {
            return (IntersectsX(rectangle1, rectangle2) || IntersectsX(rectangle2, rectangle1)) &&
                   (IntersectsY(rectangle1, rectangle2) || IntersectsY(rectangle2, rectangle1));
        }

        static bool IntersectsX(TE_Rectangle rectangle1, TE_Rectangle rectangle2)
        {
            //X collision
            var overlapping = rectangle1.Left <= rectangle2.Left && rectangle1.Right >= rectangle2.Left &&
                                  rectangle1.Right <= rectangle2.Right;

            var inside = rectangle1.Left >= rectangle2.Left && rectangle1.Right <= rectangle2.Right;

            return overlapping || inside;
        }

        static bool IntersectsY(TE_Rectangle rectangle1, TE_Rectangle rectangle2)
        {
            //Y collision
            var overlapping = rectangle1.Top <= rectangle2.Top && rectangle1.Bottom >= rectangle2.Top &&
                                  rectangle1.Bottom <= rectangle2.Bottom;

            var inside = rectangle1.Top >= rectangle2.Top && rectangle1.Bottom <= rectangle2.Bottom;

            return overlapping || inside;
        }


        /// <summary>
        /// Detects if a rectangle crosses a circle
        /// </summary>
        /// <param name="rectangle"></param>
        /// <param name="circle"></param>
        /// <returns></returns>
        public static bool Intersects(TE_Rectangle rectangle, TE_Circle circle)
        {
            return Intersects(circle, rectangle);
        }

        /// <summary>
        /// Detects if a rectangle crosses a circle
        /// </summary>
        /// <param name="circle"></param>
        /// <param name="rectangle"></param>
        /// <returns></returns>
        public static bool Intersects(TE_Circle circle, TE_Rectangle rectangle)
        {
            TE_Vector2 circleDistance = new TE_Vector2(System.Math.Abs(circle.Center.X - rectangle.X), 
                                                       System.Math.Abs(circle.Center.Y - rectangle.Y));

            if (circleDistance.X > (rectangle.Width / 2 + circle.Radius) || 
                circleDistance.Y > (rectangle.Height / 2 + circle.Radius))
                return false;

            if (circleDistance.X <= rectangle.Width/2 || circleDistance.Y <= rectangle.Height/2)
                return true;

            var cornerDistanceSquared = System.Math.Pow(circleDistance.X - rectangle.Width / 2, 2) +
                                 System.Math.Pow(circleDistance.Y - rectangle.Height / 2, 2);

            return (cornerDistanceSquared <= System.Math.Pow(circle.Radius, 2));
        }
    }
}